package schedule;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.eclipse.core.runtime.Assert;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Service;

import entity.schedule.ScheduleJob;
import lombok.Data;
import lombok.extern.log4j.Log4j;
import schedule.listener.RedisJobListener;

@Log4j
@Data
@Service("scheduleService")
public class ScheduleService {

	@Resource(name = "stdSchedulerFactory")
	private StdSchedulerFactory stdSchedulerFactory;

	@Resource(name = "scheduler")
	private Scheduler scheduler;

	public void addOrEditJob(ScheduleJob job) {
		try {
			// 添加监视日志
			scheduler.getListenerManager().addJobListener(new RedisJobListener("Mht"),
					GroupMatcher.jobGroupEquals(job.getJobGroup()));
			scheduleJobSetting(job);
			log.info("Add Or Edit Job Successfully : [" + job.getJobName() + "]");
		} catch (SchedulerException e) {
			log.error("Add Or Edit Schedule Job [" + job.getJobName() + "] Error :", e);
		}
	}

	public void pauseJob(String jobName) {
		try {
			scheduler.pauseJob(findGroupJobByName(jobName));
			log.info("Pause Schedule Job [" + jobName + "] Successfully.");
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			log.error("Pause Schedule Job [" + jobName + "] Error :", e);
		}
	}

	public void resumeJob(String jobName) {
		try {
			scheduler.resumeJob(findGroupJobByName(jobName));
			log.info("Resume Schedule Job [" + jobName + "] Successfully.");
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			log.error("Resume Schedule Job [" + jobName + "] Error :", e);
		}
	}

	public void deleteJob(String jobName) {
		try {
			scheduler.deleteJob(findGroupJobByName(jobName));
			log.info("Delete Schedule Job [" + jobName + "] Successfully.");
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			log.error("Delete Schedule Job [" + jobName + "] Error :", e);
		}
	}

	public void shutdownSchedule() {
		try {
			scheduler.shutdown(true);
			log.info("Shut Down Schedule Job Successfully.");
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			log.error("Shutdown Schedule Job Error :", e);
		}
	}

	public void getAllJobs(String jobName) {
		try {
			for (String group : scheduler.getJobGroupNames()) {
				// enumerate each job in group

				for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group))) {
					log.info("Found job identified by: " + jobKey);
				}
			}
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private GroupMatcher<JobKey> getFilterJobs(String groupName) {
		return GroupMatcher.jobGroupEquals(groupName);
	}

	private JobKey findGroupJobByName(String jobName) {
		Assert.isNotNull(jobName, "Job Name must not be null!");
		JobKey job = null;
		try {
			for (String group : scheduler.getJobGroupNames()) {
				// enumerate each job in group
				for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group))) {
					if (jobName.equals(jobKey.getName())) {
						job = jobKey;
						log.info("Found job identified by: " + jobKey);
					}
				}
			}
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			log.error("Found job error : ", e);
			return job;
		}
		return job;
	}

	@SuppressWarnings("unchecked")
	private void scheduleJobSetting(ScheduleJob job) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());

			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

			if (null == trigger) {
				// New
				JobDetail jobDetail = JobBuilder.newJob(job.getClazz())
						.withIdentity(job.getJobName(), job.getJobGroup()).build();
				jobDetail.getJobDataMap().put(job.getJobKey(), job);

				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

				trigger = (CronTrigger) TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
						.withSchedule(scheduleBuilder).build();
				log.info("新增作业名称为:" + job.getJobName() + " 作业详情为:" + trigger.getExpressionSummary());
				scheduler.scheduleJob(jobDetail, trigger);
			} else {
				// Edit
				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

				trigger = (CronTrigger) trigger.getTriggerBuilder().withIdentity(triggerKey)
						.withSchedule(scheduleBuilder).build();
				log.info("修改作业名称为:" + job.getJobName() + " 作业详情为:" + trigger.getExpressionSummary());
				scheduler.rescheduleJob(triggerKey, trigger);
			}
		} catch (SchedulerException e) {
			log.error("Initialize Schedule Job Error : " + e.toString());
		}
	}

	/**
	 * 获取所有计划中的任务列表
	 * 
	 * @return
	 * @throws SchedulerException
	 */
	public List<ScheduleJob> getAllJob() throws SchedulerException {
		GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
		Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
		List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
		for (JobKey jobKey : jobKeys) {
			List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
			for (Trigger trigger : triggers) {
				ScheduleJob job = new ScheduleJob();
				job.setJobName(jobKey.getName());
				job.setJobGroup(jobKey.getGroup());
				job.setDescription("触发器:" + trigger.getKey());
				Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
				job.setJobStatus(triggerState.name());
				if (trigger instanceof CronTrigger) {
					CronTrigger cronTrigger = (CronTrigger) trigger;
					String cronExpression = cronTrigger.getCronExpression();
					job.setCronExpression(cronExpression);
				}
				jobList.add(job);
			}
		}
		return jobList;
	}

	/**
	 * 所有正在运行的job
	 * 
	 * @return
	 * @throws SchedulerException
	 */
	public List<ScheduleJob> getRunningJob() throws SchedulerException {
		List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
		List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(executingJobs.size());
		for (JobExecutionContext executingJob : executingJobs) {
			ScheduleJob job = new ScheduleJob();
			JobDetail jobDetail = executingJob.getJobDetail();
			JobKey jobKey = jobDetail.getKey();
			Trigger trigger = executingJob.getTrigger();
			job.setJobName(jobKey.getName());
			job.setJobGroup(jobKey.getGroup());
			job.setDescription("触发器:" + trigger.getKey());
			Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
			job.setJobStatus(triggerState.name());
			if (trigger instanceof CronTrigger) {
				CronTrigger cronTrigger = (CronTrigger) trigger;
				String cronExpression = cronTrigger.getCronExpression();
				job.setCronExpression(cronExpression);
			}
			jobList.add(job);
		}
		return jobList;
	}

	/**
	 * 暂停一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void pauseJob(ScheduleJob scheduleJob) throws SchedulerException {
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.pauseJob(jobKey);
	}

	/**
	 * 恢复一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void resumeJob(ScheduleJob scheduleJob) throws SchedulerException {
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.resumeJob(jobKey);
	}

	/**
	 * 删除一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void deleteJob(ScheduleJob scheduleJob) throws SchedulerException {
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.deleteJob(jobKey);

	}

	/**
	 * 立即执行job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void runAJobNow(ScheduleJob scheduleJob) throws SchedulerException {
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.triggerJob(jobKey);
	}

	/**
	 * 更新job时间表达式
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void updateJobCron(ScheduleJob scheduleJob) throws SchedulerException {

		TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());

		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());

		trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

		scheduler.rescheduleJob(triggerKey, trigger);
	}

}